package com.eastmoney.emis.edda.application.aop;

import com.eastmoney.emis.edda.domain.service.edda.EddaBindAndDirectDebitCommand;
import com.eastmoney.emis.logger.LoggerFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @description: Description
 * @projectName: EDDA-HSBC
 * @package: com.eastmoney.emis.edda.application.aop
 * @author: 汪程程
 * @date: 2023/4/1 2:41 PM
 * @version: 1.0
 */

@Component
@Aspect
public class LockAspect {
    private static final Logger log = LoggerFactory.getLogger(LockAspect.class);
    private static final ConcurrentHashMap<String, ReentrantLock> LOCK_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
    @Pointcut("@annotation(com.eastmoney.emis.edda.application.aop.Lock)")
    public void pointcut() {

    }

    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs();
        if (!(args[0] instanceof EddaBindAndDirectDebitCommand)) {
            throw new IllegalArgumentException("不支持的参数");
        }
        EddaBindAndDirectDebitCommand command = (EddaBindAndDirectDebitCommand) args[0];
        ReentrantLock lock = getLock(command.getClientId());
        lock.lock();
        try {
            log.info("获得锁, client_id: {}, lock: {}", command.getClientId(), lock.hashCode());
            return pjp.proceed();
        } finally {
            lock.unlock();
            log.info("释放锁, client_id: {}, lock: {}", command.getClientId(), lock.hashCode());
            removeLock(command.getClientId());
        }
    }

    private ReentrantLock getLock(String clientId) {
        ReentrantLock reentrantLock = LOCK_CONCURRENT_HASH_MAP.get(clientId);
        if (reentrantLock != null) {
            return reentrantLock;
        }
        LOCK_CONCURRENT_HASH_MAP.putIfAbsent(clientId, new ReentrantLock());
        return LOCK_CONCURRENT_HASH_MAP.get(clientId);
    }

    private void removeLock(String clientId) {
        LOCK_CONCURRENT_HASH_MAP.remove(clientId);
    }


}
